/**
 * Copyright (c) Software Institute of PKU
 * All rights reserved. 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */
package edu.pku.sei.modeler.commands;

import org.eclipse.gef.commands.Command;

import edu.pku.sei.modeler.exceptions.FactoryNotFoundException;
import edu.pku.sei.modeler.model.common.ModelRegistry;
import edu.pku.sei.modeler.model.core.MetaClass;
import edu.pku.sei.modeler.model.core.MetaGeneralization;
import edu.pku.sei.modeler.model.core.MetaReference;
import edu.pku.sei.modeler.model.structure.MetaBendPoint;
import edu.pku.sei.modeler.model.structure.MetaLink;
import edu.pku.sei.modeler.model.structure.MetaNode;
import edu.pku.sei.modeler.model.structure.StructureFactory;
/**
 * @author zl
 *
 */
public class CreateLinkCommand extends Command {
	protected MetaLink link;
	protected MetaNode source, target;
	protected ModelCommand modelCmd;
	
	public CreateLinkCommand(MetaLink newObj, MetaNode src) {
		super("Link Creation");
		link = newObj;
		source = src;
		if(link.getModelElement() instanceof MetaReference) {
			modelCmd = new CreateAssoCommand(
					link.getModelElement(), src.getModelElement());
		}
		else if(link.getModelElement() instanceof MetaGeneralization) {
			modelCmd = new CreateGenCommand(
					link.getModelElement(), src.getModelElement());
		}
	}
	
	public CreateLinkCommand(MetaLink newObj, MetaNode src, ModelCommand cmd) {
		this.link = newObj;
		this.source = src;
		this.modelCmd = cmd;
	}

	public boolean canExecute() {
		boolean result = source != null && target != null && link != null;
		if(modelCmd != null)
			result |= modelCmd.canExecute();
		return result;
	}

	public void execute() {
		if (source == target) {
			StructureFactory sFactory;
			try {
				sFactory = (StructureFactory)ModelRegistry.getRegistry().getStructureFactory(link.getModelElement().getModel());
				MetaBendPoint p = sFactory.createMetaBendPoint(); 
				MetaBendPoint p1 = sFactory.createMetaBendPoint();
				MetaBendPoint p2 = sFactory.createMetaBendPoint();
				MetaBendPoint p3 = sFactory.createMetaBendPoint();
				p.x = source.getLocationX();
				p.y = source.getLocationY();
				
				p1.x = p.x - 10;
				p1.y = p.y + 10;
				p2.x = p.x - 10;
				p2.y = p.y - 10;
				p3.x = p.x + 10;
				p3.y = p.y - 10;
				
				link.getBendPoints().add(p1);
				link.getBendPoints().add(p2);
				link.getBendPoints().add(p3);
			} catch (IllegalArgumentException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (FactoryNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		if(modelCmd != null && !link.isReferenceShape())
			modelCmd.execute();
		
		//FIXME: This statement has an non-local-handled exception
		link.setSource(source);
		source.getOutgoings().add(link);
		link.setTarget(target);
		target.getIncomings().add(link);
//		link.setModel(source.getModel());
//		source.getDiagram().getConnections().add(link);
	}

	public void setTarget(MetaNode target) {
		this.target = target;
		if(modelCmd != null) {
			modelCmd.setTarget(target.getModelElement());
		}
	}

	public void undo() {
		link.setSource(null);
		link.setTarget(null);
		if (source == target) {
			link.getBendPoints().clear();
		}
		if(modelCmd != null)
			modelCmd.undo();
	}
	
	private class CreateAssoCommand extends ModelCommand
	{
		private MetaClass src, des;
		private MetaReference ref;
		
		public CreateAssoCommand(Object ref, Object src) {
			this.ref = (MetaReference)ref;
			if(src instanceof MetaClass)
				this.src = (MetaClass)src;
		}
		
		public void setTarget(Object des) {
			if(des instanceof MetaClass)
				this.des = (MetaClass)des;
		}
		
		public boolean canExecute() {
			return true;
		}
		
		public void execute() {
			if(src != null)
				src.getReferences().add(ref);
			if(ref != null) {
				ref.setContainer(src);
				ref.setType(des);
//				ref.setModel(src.getModel());
			}
		}
		
		public void undo() {
			
		}
	}
	private class CreateGenCommand extends ModelCommand
	{
		private MetaClass src, des;
		private MetaGeneralization gen;
		
		public CreateGenCommand(Object gen, Object src) {
			this.gen = (MetaGeneralization)gen;
			if(src instanceof MetaClass)
				this.src = (MetaClass)src;
		}
		
		public void setTarget(Object des) {
			if(des instanceof MetaClass)
				this.des = (MetaClass)des;
		}
		
		public boolean canExecute() {
			return true;
		}
		
		public void execute() {
			if(src != null)
				src.getGenerals().add(gen);
			if(gen != null) {
				gen.setContainer(src);
				gen.setGeneral(des);
//				gen.setModel(src.getModel());
			}
		}
		
		public void undo() {
			
		}
	} 
}
